package com.li.temperature.chart.service;

import java.util.ArrayList;
import java.util.List;

import org.ujmp.core.Matrix;

import android.content.Context;
import android.util.Log;

import com.li.temperature.chart.bean.FileNode;
import com.li.temperature.chart.bean.T10FileNode;
import com.li.temperature.chart.bean.T11FileNode;
import com.li.temperature.chart.bean.T12FileNode;
import com.li.temperature.chart.bean.T13FileNode;
import com.li.temperature.chart.bean.T14FileNode;
import com.li.temperature.chart.bean.T1FileNode;
import com.li.temperature.chart.bean.T2FileNode;
import com.li.temperature.chart.bean.T3FileNode;
import com.li.temperature.chart.bean.T4FileNode;
import com.li.temperature.chart.bean.T5FileNode;
import com.li.temperature.chart.bean.T6FileNode;
import com.li.temperature.chart.bean.T7FileNode;
import com.li.temperature.chart.bean.T8FileNode;
import com.li.temperature.chart.bean.T9FileNode;
import com.li.temperature.chart.impl.IPhoneStatusObserver;
import com.li.temperature.chart.impl.IPhoneStatusResult;
import com.li.temperature.chart.util.ConfigA;
import com.li.temperature.chart.util.Constant;
import com.li.temperature.chart.util.DateTimeUtil;
import com.li.temperature.chart.util.LogUtil;
import com.li.temperature.chart.util.ShareUtil;

public class PhoneStatusManager {

    private Context mContext;

    private int matrixType = ConfigA.A_F_20s;

    private static String mCurrentTimeStr;

    private List<Double> mXList;

    private Matrix mMatrix_X;
    private List<Double> mResultList;
    private List<FileNode> mList;

    /**
     * 每2秒进行一次计算，用的是当前采样值和5秒前的采样值
     */
    private int count;
    private static final int PERIOD = 2;
    private static int LIST_MAX_SIZE = 10;
    private List<List<Double>> mUpdateList;

    public static PhoneStatusManager mInstance;

    public static PhoneStatusManager getInstance(Context context) {
        if (mInstance == null) {
            synchronized (PhoneStatusManager.class) {
                if (mInstance == null) {
                    mInstance = new PhoneStatusManager(context);
                }
            }
        }
        return mInstance;
    }

    public PhoneStatusManager(Context context) {
        this.mContext = context;
        mResultList = new ArrayList<Double>();
        mUpdateList = new ArrayList<List<Double>>();
        mXList = new ArrayList<Double>();

        mList = new ArrayList<FileNode>();
        mList.add(new T1FileNode(mContext));
        mList.add(new T2FileNode(mContext));
        mList.add(new T3FileNode(mContext));
        mList.add(new T4FileNode(mContext));
        mList.add(new T5FileNode(mContext));
        mList.add(new T6FileNode(mContext));
        mList.add(new T7FileNode(mContext));
        mList.add(new T8FileNode(mContext));
        mList.add(new T9FileNode(mContext));
        mList.add(new T10FileNode(mContext));
        mList.add(new T11FileNode(mContext));
        mList.add(new T12FileNode(mContext));

        writeLogType(mList);
        writeResultLogType();
    }

    private void writeLogType(List<FileNode> list) {
        StringBuilder sb = new StringBuilder();
        sb.append("Time ");
        for (FileNode mFileNode : list) {
            sb.append(mFileNode.name + " ");
        }
        LogUtil.writeLogTypeFile(sb.toString());
    }

    private void writeResultLogType() {
        StringBuilder sb = new StringBuilder();
        sb.append("Time ");
        for (int i = 0; i < ConfigA.MATRIX_A_15.getColumnCount(); i++) {
            sb.append("Y" + (i + 1) + " ");
        }
        sb.append("T13");
        LogUtil.writeResultLogTypeFile(sb.toString());
    }

    private IPhoneStatusObserver mIPhoneStatusObserver;

    public void setIPhoneStatusObserver(IPhoneStatusObserver mIPhoneStatusObserver) {
        this.mIPhoneStatusObserver = mIPhoneStatusObserver;
    }

    public void startMonitor() {
        count = 0;
        if (null != mIPhoneStatusObserver) {
            mIPhoneStatusObserver.updateStatus(PhoneStatusService.STATUS_RUNNING);
        }

        matrixType = getPredictionStep();

        LogUtil.delLogFile();
        LogUtil.delResultLogFile();
    }

    private IPhoneStatusResult mIPhoneStatusResult;

    public void setIPhoneStatusResult(IPhoneStatusResult mIPhoneStatusResult) {
        this.mIPhoneStatusResult = mIPhoneStatusResult;
    }

    public void stopMonitor() {
        count = 0;
        if (null != mIPhoneStatusObserver) {
            mIPhoneStatusObserver.updateStatus(PhoneStatusService.STATUS_STOP);
        }
    }

    private int getPredictionStep() {
        return new ShareUtil(mContext).getInt(ConfigA.KEY_PREDICT_STEP, ConfigA.A_F_20s);
    }

    public void updateMonitor() {
        mCurrentTimeStr = DateTimeUtil.getSysTime();
        updateCurrenData();
    }

    private void updateCurrenData() {
        StringBuilder sb = new StringBuilder();
        sb.append(mCurrentTimeStr);
        sb.append(" ");

        List<Double> mData = new ArrayList<Double>();

        for (FileNode item : mList) {
            item.updateData();
            sb.append(item.valueStr);
            sb.append(" , ");
            mData.add(item.valueDoule);
        }

        if (mUpdateList.size() == LIST_MAX_SIZE) {
            mUpdateList.remove(0);
        }

        mUpdateList.add(mData);

        if (count == PERIOD) {
            updateXData();
            count = 0;
        }

        count++;

        LogUtil.writeLogFile(sb.toString());
    }

    private void updateXData() {
        mXList.clear();

        if (mUpdateList != null && mUpdateList.size() == LIST_MAX_SIZE) {
            /**
             * 排列格式
             * X=[T1(t),…,T12(t),T1(t-5),…,T12(t-5) ,T1(t-10),…,T12(t-10)]
             */
            int tIndex = LIST_MAX_SIZE - 1;
            mXList.addAll(mUpdateList.get(tIndex));

            int t5Index = 4;// 顺序是从0开始，故t5秒的index为4
            mXList.addAll(mUpdateList.get(t5Index));

            int t10Index = 0;
            mXList.addAll(mUpdateList.get(t10Index));
            //Log.d(Constant.TAG, mUpdateList.toString());
        }

        StringBuilder sb = new StringBuilder();
        for (Double item : mXList) {
            sb.append(item);
            sb.append(" ");
        }

        //if (null != mIPhoneStatusObserver) {
            //mIPhoneStatusObserver.updateXData(sb.toString());
        //}

        if (mXList != null && !mXList.isEmpty()) {
            list2MatrixForX(mXList);

            multiplication();
        }
    }

    private void list2MatrixForX(List<Double> list) {
        mMatrix_X = Matrix.Factory.zeros(1, list.size());
        for (int i = 0; i < list.size(); i++) {
            /** value, row, column */
            mMatrix_X.setAsDouble(list.get(i), 0, i);
        }
        //Log.d(Constant.TAG, mMatrix_X.toString() + ", list.size() = " + list.size());
    }

    private void multiplication() {
        Log.d(Constant.TAG, "Cal start - Matrix_X = " + mMatrix_X.toString());

        Matrix mMatrix_Y = null;

        switch (matrixType) {
        case ConfigA.A_F_10s:
            // Log.d(Constant.TAG, "Coefficient_10 = " +
            // ConfigA.MATRIX_A_10.toString());
            mMatrix_Y = mMatrix_X.mtimes(ConfigA.MATRIX_A_10);
            break;
        case ConfigA.A_F_15s:
            // Log.d(Constant.TAG, "Coefficient_15 = " +
            // ConfigA.MATRIX_A_20.toString());
            mMatrix_Y = mMatrix_X.mtimes(ConfigA.MATRIX_A_15);
            break;
        case ConfigA.A_F_20s:
            // Log.d(Constant.TAG, "Coefficient_20 = " +
            // ConfigA.MATRIX_A_15.toString());
            mMatrix_Y = mMatrix_X.mtimes(ConfigA.MATRIX_A_20);
            break;
        default:
            break;
        }

        Log.d(Constant.TAG, "Cal end - Matrix_Y = " + mMatrix_Y.toString());

        updateXResultData(mMatrix_Y);
    }

    private void updateXResultData(Matrix mMatrix_Y) {
        mResultList.clear();

        double y1 = mMatrix_Y.getAsDouble(0, 0);
        mResultList.add(y1);

        FileNode T13FileNode = new T13FileNode(mContext);
        double T13 = 0.0;
        if (T13FileNode.isRead) {
            T13FileNode.updateData();
            T13 = T13FileNode.valueDoule;
        }

        Log.d(Constant.TAG, "update result y1 = " + y1 + ", T13 = " + T13);
        if (mIPhoneStatusResult != null) {
            mIPhoneStatusResult.updateResult(matrixType, y1, T13);
        }

        StringBuilder sb = new StringBuilder();
        sb.append(mCurrentTimeStr);
        sb.append(" ");
        sb.append(String.format("%.1f", y1));
        sb.append(" ");
        sb.append(String.format("%.1f", T13));
        LogUtil.writeResultLogFile(sb.toString());
    }
}
